package com.online.questionnaire.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.online.questionnaire.common.*;
import com.online.questionnaire.constant.UserConstant;
import com.online.questionnaire.exception.ThrowUtils;
import com.online.questionnaire.model.User;
import com.online.questionnaire.model.dto.FileDTO;
import com.online.questionnaire.service.UserService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文件上传
 */
@RestController
@RequestMapping("/files")
@Slf4j
@Tag(name = "上传接口")
public class FileController {


    @Resource
    private UserService userService;

    //只允许这些后缀保存
    String[] filterSuffix = new String[]{".jpg",".png",".jpeg",".ico",".jfif",".webp"};
    List<String> fileSuffixList = new ArrayList<>(Arrays.asList(filterSuffix));

    @Value("${server.port}")
    Integer port;
    @Value("${ip}")
    String ip;

    public String getUrl(){
        return "http://" + ip + ":" + port + "/api/upload/";
    }

    public static String savePath = File.separator + "src" + File.separator + "main" + File.separator +
            "resources" + File.separator + "static"+ File.separator +"upload" + File.separator;

    /**
     * 修改头像接口
     */
    @PostMapping("/updateAvatar")
    public R<String> updateAvatar(MultipartFile file, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null){
            ThrowUtils.notLoginError();
        }
        //文件后缀名
        String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        if (!fileSuffixList.contains(suffixName)){
            return ResultUtils.error(ErrorCode.PARAMS_ERROR,"上传文件格式错误");
        }
        //保存文件到 resources/static/upload/
        String fileName = IdUtil.simpleUUID() + suffixName;
        try {
            String property = System.getProperty("user.dir");
            log.info("文件保存路径：" + property + savePath + fileName);
            File saveFile = new File(property + savePath + fileName);
            file.transferTo(saveFile);
            //开发环境拷贝到target目录
            File targetFile = new File(ResourceUtils.getURL("classpath:").getPath());
            // 生产环境 不存在 target/classes 目录
            if (!targetFile.exists()) {
                // 获取当前运行目录
                targetFile = new File("");
            }

            File uploadTarget = new File(targetFile.getAbsolutePath(), "static/upload");
            if (!uploadTarget.exists()) {
                uploadTarget.mkdirs();
            }
            FileCopyUtils.copy(saveFile, new File(uploadTarget, fileName));

            String s = "http://" + ip + ":" + port + "/api/upload/" + fileName;
            //保存到 数据库
            loginUser.setUserAvatar(s);
            userService.updateById(loginUser);

            return ResultUtils.success(s);

        } catch (Exception e) {
            log.error("上传文件失败", e);
            return ResultUtils.error(ErrorCode.OPERATION_ERROR,"上传失败");
        }

    }

    /**
     * 富文本编辑器上传图片接口
     * 背景图上传
     * @param file
     * @param request
     * @return
     */
    @PostMapping("/upload")
    public EditorRes upload(MultipartFile file, HttpServletRequest request) {
        EditorRes editorRes = new EditorRes();
        if (file == null){
            editorRes.setErrno(1);
            editorRes.setMessage("上传文件为空");
            return editorRes;
        }
        //文件后缀名
        String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        if (!fileSuffixList.contains(suffixName)){
            editorRes.setErrno(1);
            editorRes.setMessage("上传文件格式错误");
            return editorRes;
        }

        //保存文件到 resources/static/upload/
        String fileName = IdUtil.simpleUUID() + suffixName;
        try {
            String property = System.getProperty("user.dir");
            log.info("文件保存路径：" + property + savePath + fileName);
            File saveFile = new File(property + savePath + fileName);
            file.transferTo(saveFile);
            //开发环境拷贝到target目录
            File targetFile = new File(ResourceUtils.getURL("classpath:").getPath());
            // 生产环境 不存在 target/classes 目录
            if (!targetFile.exists()) {
                // 获取当前运行目录
                targetFile = new File("");
            }

            File uploadTarget = new File(targetFile.getAbsolutePath(), "static/upload");
            if (!uploadTarget.exists()) {
                uploadTarget.mkdirs();
            }
            FileCopyUtils.copy(saveFile, new File(uploadTarget, fileName));

            String s = "http://" + ip + ":" + port + "/api/upload/" + fileName;
            editorRes.setErrno(0);
            editorRes.setMessage("上传成功");
            EditorData editorData = new EditorData();
            editorData.setUrl(s);
            editorData.setHref(s);
            editorRes.setData(editorData);
            return editorRes;

        } catch (Exception e) {
            log.error("上传文件失败", e);
            editorRes.setErrno(1);
            editorRes.setMessage("上传失败:" + e.getMessage());
            return editorRes;
        }
    }

    /**
     * 获取系统文件列表
     * 管理员
     * type -1 全部文件  0 图片  1其他文件(xlsx)
     */
    @GetMapping("/list")
    public R<IPage<FileDTO>> list(int page, int size,int type,
                                  HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null){
            ThrowUtils.notLoginError();
        }
        if (!loginUser.getUserRole().equals(UserConstant.ADMIN_ROLE)){
            ThrowUtils.authError();
        }
        String property = System.getProperty("user.dir");
        List<String> strings = FileUtil.listFileNames(property + savePath);
        if (type == 0){
            strings = strings.stream().filter(s -> fileSuffixList.contains(s.substring(s.lastIndexOf(".")))).collect(Collectors.toList());
        }else if (type == 1){
            strings = strings.stream().filter(s -> !fileSuffixList.contains(s.substring(s.lastIndexOf(".")))).collect(Collectors.toList());
        }
        List<FileDTO> fileDTOList = new ArrayList<>();
        Integer allSize = strings.size();
        //分页
        if (page > 0 && size > 0){
            int start = (page - 1) * size;
            int end = Math.min(start + size, strings.size());
            strings = strings.subList(start, end);
        }
        //获取文件修改日期以及后缀
        for (int i = 0; i < strings.size(); i++) {
            File file = new File(property + savePath + strings.get(i));
            FileDTO fileDTO = new FileDTO();
            fileDTO.setFileName(strings.get(i));
            fileDTO.setFileSize(file.length());
            long l = file.lastModified();
            //转成字符串时间
            fileDTO.setUpdateTime(DateUtil.format(new Date(l), "yyyy-MM-dd HH:mm:ss"));
            fileDTO.setSuffix(strings.get(i).substring(strings.get(i).lastIndexOf(".")));
            //检查后缀是否为图片
            if (fileSuffixList.contains(fileDTO.getSuffix())){
                fileDTO.setType(0);
            }else {
                fileDTO.setType(1);
            }
            //设置预览路径
            fileDTO.setUrl(getUrl() + fileDTO.getFileName());
            fileDTOList.add(fileDTO);
        }
        IPage<FileDTO> fileDTOPage = new Page<>();
        fileDTOPage.setRecords(fileDTOList);
        fileDTOPage.setTotal(allSize);
        fileDTOPage.setSize(size);
        fileDTOPage.setCurrent(page);

        return ResultUtils.success(fileDTOPage);
    }

    /**
     * 删除文件 根据文件名
     */
    @GetMapping("/delete")
    public R<String> delete(String fileName, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null){
            ThrowUtils.notLoginError();
        }
        if (!loginUser.getUserRole().equals(UserConstant.ADMIN_ROLE)){
            ThrowUtils.authError();
        }
        String property = System.getProperty("user.dir");
        File file = new File(property + savePath + fileName);
        if (file.exists()){
            file.delete();
            return ResultUtils.success("删除成功");
        }
        return ResultUtils.error(ErrorCode.OPERATION_ERROR,"文件不存在");
    }

    /**
     * 清空所有xlsx文件
     */
    @GetMapping("/clear/xlsx")
    public R<Integer> clearXlsx(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        if (loginUser == null){
            ThrowUtils.notLoginError();
        }
        if (!loginUser.getUserRole().equals(UserConstant.ADMIN_ROLE)){
            ThrowUtils.authError();
        }
        String property = System.getProperty("user.dir");
        List<String> strings = FileUtil.listFileNames(property + savePath);
        int count = 0;
        for (int i = 0; i < strings.size(); i++) {
            if (strings.get(i).endsWith(".xlsx")){
                File file = new File(property + savePath + strings.get(i));
                file.delete();
                count++;
            }
        }
        return new R<>(0, count,"删除成功，共" + count + "条");

    }

    /**
     * 根据文件名称下载文件
     */
    @GetMapping("/download")
    public void download(String fileName, HttpServletResponse response) throws IOException {
        String name = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");  // 编码，并替换空格
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=" + fileName);
        response.setHeader("Access-Control-Expose-Headers","Content-Disposition, X-Custom-Header");

        ServletOutputStream outputStream = response.getOutputStream();
        String property = System.getProperty("user.dir");
        outputStream.write(FileUtil.readBytes(property + savePath + fileName));
        outputStream.flush();
        outputStream.close();
    }
}
